﻿using System;
using System.IO;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.Xml;
using ilibrary.source.model;
using Log;
using System.Collections.Generic;

namespace ilibrary.source.views
{
    public partial class PersonalNotesEditor : Form
    {
        private EventLog log = new EventLog("ILibrary", "PersonalNotesEditor");

        private int ebookId;
        private string ebookTitle;
        private RichTextBox richTextBoxToSave = new RichTextBox();

        #region Constructors
        public PersonalNotesEditor()
        {
            InitializeComponent();

            if (!init(null))
            {
                MessageBox.Show("Une erreur est survenue lors de l'ouverture de la fenêtre.\nL'ebook sélectionné ne semble pas avoir de table des matières.", "ILibrary error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                throw new Exception("TreeView couldn't be initialized");
            }
        }

        public PersonalNotesEditor(EBook ebook)
        {
            InitializeComponent();

            if (!init(ebook))
            {
                MessageBox.Show(
                    "Une erreur est survenue lors de l'ouverture de la fenêtre.\nL'ebook sélectionné ne semble pas avoir de table des matières.",
                    "ILibrary error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation,
                    MessageBoxDefaultButton.Button1);
                throw new Exception("TreeView couldn't be initialized");
            }
        }

        private bool init(EBook ebook)
        {
            try
            {
                // Ne pas le mettre dans le Designer sinon plantage au RunTime
                // car ces propriétés précèdent la propriété Size
                this.splitContainerMain.Panel1MinSize = 120;
                this.splitContainerMain.Panel2MinSize = 300;

                if (ebook != null)
                {
                    this.ebookId = ebook.Id;
                    this.ebookTitle = ebook.Title;
                    return initTreeView(ebook);
                }
                return false;
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return false;
            }
        }

        private bool initTreeView(EBook ebook)
        {
            try
            {
                this.treeViewTOC.BeginUpdate();

                TreeNode currentNode = treeViewTOC.Nodes.Add(ebook.Title, ebook.Title);
                XmlReader reader = XmlReader.Create(new StringReader(ebook.getTOC(null)));
                
                while (reader.Read())
                {
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element:
                            if (string.Compare(reader.Name, "toc") == 0)
                                if (currentNode.LastNode != null)
                                    currentNode = currentNode.LastNode;
                            break;

                        case XmlNodeType.EndElement:
                            if (string.Compare(reader.Name, "toc") == 0)
                                currentNode = currentNode.Parent;
                            break;

                        case XmlNodeType.Text:
                            currentNode.Nodes.Add(reader.Value, reader.Value);
                            break;

                        default:
                            break;
                    }
                }
                reader.Close();

                this.treeViewTOC.ExpandAll();
                return true;
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return false;
            }
            finally
            {
                this.treeViewTOC.EndUpdate();
            }
        }
        #endregion

        #region Save Functions
        /// <summary>
        /// Enregistre les notes de chaque onglet
        /// </summary>
        private void save()
        {
            try
            {
                foreach (TabPage page in this.tabControl.TabPages)
                {
                    Control[] textEditors = page.Controls.Find("TextEditor", false);
                    if (textEditors.Length == 1)
                    {
                        TextEditor textEditor = textEditors[0] as TextEditor;
                        if (textEditor == null)
                            this.log.Warn("The unique control of the TabPage isn't a TextEditor");
                        else if (textEditor.Modified)
                        {
                            save(page.Text, textEditor.RichText);
                            textEditor.Modified = false;
                        }
                    }
                    else
                        this.log.Warn("TabPage without TextEditor existing");
                }
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
        }
        /// <summary>
        /// Enregistre les notes d'un onglet
        /// </summary>
        /// <param name="tabPageName">Nom de l'onglet (correspond à l'index dans le treeview)</param>
        /// <param name="personalNotes">Notes à enregistrer</param>
        private void save(string tabPageText, string personalNotes)
        {
            try
            {
                TreeNode[] treeNodes = treeViewTOC.Nodes.Find(tabPageText, true);
                if (treeNodes.Length == 1)
                {
                    TreeNode node = treeNodes[0];
                    Library.Instance.UpdatePersonalNotes(this.ebookId, node.FullPath, personalNotes);
                }
                else if (treeNodes.Length != 0)
                    log.Warn("Some nodes have the same key");
                else
                    log.Warn(string.Concat("The node with key ", tabPageText, " doesn't exist"));
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
        }
        #endregion

        private void openOrSelectTab(TreeNode node)
        {
            try
            {
                int tabIndex = this.tabControl.TabPages.IndexOfKey(node.FullPath);
                if (tabIndex >= 0) // Un onglet pour ce chapitre est déjà ouvert
                    this.tabControl.SelectedIndex = tabIndex;
                else
                {
                    try
                    {
                        this.tabControl.SuspendLayout();
                        // Ajout d'un onglet et affichage de celui-ci
                        this.tabControl.TabPages.Add(node.FullPath, node.Name);
                        this.tabControl.SelectedIndex = this.tabControl.TabPages.Count - 1;
                        TabPage page = this.tabControl.SelectedTab;
                        page.ToolTipText = page.Text;

                        // Récupération des notes si elles existent
                        string richText = string.Empty;
                        if (Library.Instance.PersonalNotesExist(this.ebookId, node.FullPath))
                            richText = Library.Instance.SelectPersonalNotes(this.ebookId, node.FullPath);
                        else
                            Library.Instance.AddPersonalNotes(this.ebookId, node.FullPath, richText);

                        // Ajout d'un TextEditor dans l'onglet
                        TextEditor textEditor = new TextEditor(richText);
                        textEditor.Dock = DockStyle.Fill;
                        textEditor.Save += new EventHandler(textEditor_Save);
                        page.Controls.Add(textEditor);
                    }
                    catch (Exception ex)
                    {
                        this.log.Error("", ex);
                    }
                    finally
                    {
                        this.tabControl.ResumeLayout(false);
                        this.tabControl.PerformLayout();
                    }
                }
                this.label.Visible = false;
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        #region MenuEvents
        private void toolStripMenuItemSave_Click(object sender, EventArgs e)
        {
            try
            {
                this.toolStripStatusLabel.Text =
                    string.Concat("Enregistrement en cours");

                save();

                this.toolStripStatusLabel.Text =
                    string.Concat("Enregistrement effectué");
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        private void toolStripMenuItemSaveAsFile_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            try
            {
                saveFileDialog.DefaultExt = ".rtf";
                saveFileDialog.FileName = this.ebookTitle;
                saveFileDialog.Filter = "Rich Text File (*.rtf)|*.rtf";
                saveFileDialog.Title = string.Concat("Enregistrer les notes de ", saveFileDialog.FileName);

                if (saveFileDialog.ShowDialog() != DialogResult.OK)
                    return;

                this.richTextBoxToSave.Clear();

                foreach (TreeNode node in this.treeViewTOC.Nodes)
                {
                    this.richTextBoxToSave.Rtf +=
                        Library.Instance.SelectPersonalNotes(this.ebookId, node.FullPath);
                    this.richTextBoxToSave.AppendText("\n\n_______________________\n\n");
                }

                this.richTextBoxToSave.SaveFile(saveFileDialog.FileName, RichTextBoxStreamType.RichText);

                this.toolStripStatusLabel.Text =
                    string.Concat("Enregistrement de ", saveFileDialog.FileName, " effectué");
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
            finally
            {
                saveFileDialog.Dispose();
            }
        }

        private void toolStripMenuItemClose_Click(object sender, EventArgs e)
        {
            try
            {
                this.Close();
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        private void toolStripMenuItemHideTOC_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                this.splitContainerMain.Panel1Collapsed =
                    this.toolStripMenuItemHideTOC.Checked;

                if (this.splitContainerMain.Panel1Collapsed)
                    this.toolStripStatusLabel.Text =
                        string.Concat("Table des matières masquée");
                else
                    this.toolStripStatusLabel.Text =
                        string.Concat("Table des matières affichée");
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        private void toolStripMenuItemOnTop_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                this.TopMost = toolStripMenuItemOnTop.Checked;
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
        }
        #endregion

        #region TreeViewEvents
        private void treeViewTOC_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            try
            {
                this.treeViewTOC.SelectedNode = e.Node;
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        private void treeViewTOC_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            try
            {
                openOrSelectTab(e.Node);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
        }
        #endregion

        #region ContextMenuTreeViewEvents
        private void contextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                this.contextMenuStripTreeViewTOC.Items.Clear();
                Point p = this.treeViewTOC.PointToClient(this.contextMenuStripTreeViewTOC.Location);
                TreeNode node = this.treeViewTOC.GetNodeAt(p);

                if (node != null)
                {
                    this.contextMenuStripTreeViewTOC.Items.Add(
                        "Editer",
                        null,
                        new EventHandler(this.toolStripMenuItemEdit_Click));
                }
                else
                    e.Cancel = true;
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        private void toolStripMenuItemEdit_Click(object sender, EventArgs e)
        {
            try
            {
                openOrSelectTab(treeViewTOC.SelectedNode);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
        }
        #endregion

        #region TextEditorEvents
        void textEditor_Save(object sender, EventArgs e)
        {
            try
            {
                TextEditor textEditor = sender as TextEditor;
                if (textEditor == null) throw new ArgumentException("Bad sender");

                if (textEditor.Modified)
                {
                    save(this.tabControl.SelectedTab.Text, textEditor.RichText);
                    textEditor.Modified = false;
                }

                this.toolStripStatusLabel.Text =
                    string.Concat("Enregistrement de ", this.tabControl.SelectedTab.Text, " effectué");
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
        }
        #endregion

        #region PersonalNotesEditorEvents
        private void PersonalNotesEditor_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                foreach (TabPage page in this.tabControl.TabPages)
                {
                    Control[] textEditors = page.Controls.Find("TextEditor", false);
                    if (textEditors.Length == 1)
                    {
                        TextEditor textEditor = textEditors[0] as TextEditor;
                        if (textEditor == null)
                            this.log.Warn("The unique control of the TabPage isn't a TextEditor");
                        else if (textEditor.Modified)
                        {
                            this.tabControl.SelectedTab = page;
                            DialogResult dialogResult = MessageBox.Show(
                                string.Concat("Voulez-vous enregistrer les modifications apportées à ",
                                    page.Text,
                                    " ?"),
                                "ILibrary",
                                MessageBoxButtons.YesNoCancel,
                                MessageBoxIcon.Question,
                                MessageBoxDefaultButton.Button1);

                            if (dialogResult == DialogResult.Yes)
                            {
                                save(page.Text, textEditor.RichText);
                                textEditor.Modified = false;
                            }
                            else if (dialogResult == DialogResult.Cancel)
                            {
                                e.Cancel = true;
                                this.toolStripStatusLabel.Text =
                                    string.Concat("Fermeture annulée");
                                break;
                            }
                        }
                    }
                    else
                        this.log.Warn("TabPage without TextEditor existing");
                }
            }
            catch (Exception ex)
            {
                log.Error("", ex);
            }
        }
        #endregion

        #region DragAndDrop
        private void treeViewTOC_ItemDrag(object sender, ItemDragEventArgs e)
        {
            try
            {
                TreeNode node = e.Item as TreeNode;
                if (node != null)
                {
                    this.treeViewTOC.DoDragDrop(node, DragDropEffects.All);
                }
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        private void tabControl_DragEnter(object sender, DragEventArgs e)
        {
            try
            {
                e.Effect = DragDropEffects.All;
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        private void tabControl_DragDrop(object sender, DragEventArgs e)
        {
            try
            {
                TreeNode node = e.Data.GetData(treeViewTOC.Nodes[0].GetType()) as TreeNode;
                if (node != null)
                {
                    openOrSelectTab(node);
                }
                e.Effect = DragDropEffects.None;
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }
        #endregion
    }
}
